﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Meta.Numerics.Statistics.Distributions;

namespace ExcelAddIn1
{
    /**
     * Implementation of the Jarque-Bera test.
     */
    class Test_JarqueBera : Test
    {
        public Test_JarqueBera(DataContainer data)
        {
            this.data = data;
            res = new List<String>();
        }

        public override string GetInfo()
        {
            String s = "Performs a Jarque-Bera test to check if datasets are normally distributed. ";
            s += "Note that the test requires large datasets to be accurate (n > 2000).";
            return s;
        }
            
        public override void RunTest()
        {
            res.Add("Jarque-Bera test for normally distributed data");
            res.Add("");

            for (int i = 0; i < data.GetNoSets(); i++)
            {
                RunTest(i);
            }
        }

        public void RunTest(int i1)
        {
            DataSet d = data.GetDataSet(i1);

            double n = (double)d.GetN();
            double stdev = d.GetStDev();
            double mean = d.GetMean();
            double sum2 = 0.0;
            double sum3 = 0.0;
            double sum4 = 0.0;

            for (int i = 0; i < d.GetN(); i++)
            {
                double v = d.GetValue(i);
                sum2 += Math.Pow(v - mean, 2);
                sum3 += Math.Pow(v - mean, 3);
                sum4 += Math.Pow(v - mean, 4);
            }

            //Calculate Skew
            double S = (1.0 / n * sum3) / Math.Pow(1.0 / n * sum2, 3 / 2);
            //Calculate Kurtosis
            double K = (1.0 / n * sum4) / Math.Pow(1.0 / n * sum2, 2);

            //Calculate JB
            double JB = n / 6.0 * (Math.Pow(S, 2) + 0.25 * Math.Pow(K - 3.0, 2));

            //Find Critical ChiSquare
            //Note: ChiSquare is an approximation that works best for 
            //large sample sizes (>100).
            ChiSquaredDistribution csd = new ChiSquaredDistribution(2);
            double JBc = csd.InverseRightProbability(alpha);

            res.Add(";" + d.GetName() + ";;-");
            res.Add("Skew (≈0);" + S.ToString("F2"));
            res.Add("Kurtosis (≈3);" + K.ToString("F2"));
            res.Add("JB-score;" + JB.ToString("F2"));
            res.Add("JB-crit;" + JBc.ToString("F2"));
            if (JB < JBc)
            {
                res.Add("Result;Normally distributed");
            }
            else if (JB < JBc * 2.0 && n <= 200)
            {
                res.Add("Result;Possibly normally distributed");
            }
            else
            {
                res.Add("Result;Not normally distributed");
            }
            res.Add(";;;-");
        }
    }
}
